Skip to content

Conversation

@itsmeichigo
Copy link
Contributor

@itsmeichigo itsmeichigo commented Oct 13, 2025

Closes WOOMOB-1450

Description

There are crash reports regarding the removal of retried requests when flagging sites as unsupported for application passwords. These are caused by the race condition when the list of retried requests is altered simultaneously from different threads.

This PR fixes the crash by ensuring that the retried request list is updated atomically with a barrier block.

Testing steps

It's not straightforward to reproduce race conditions so it's tricky to test the crash. Simply smoke testing the flow should be sufficient.

Use the test plan in pe5sF9-4Am-p2 - run TC4. Confirm that the app doesn't crash.

Testing information

  • Added a unit test to confirm the race condition fix. The test fails before the fix.
  • Ran TC4 with simulator iPhone 17 and confirmed the app doesn't crash.

Screenshots

N/A


  • I have considered if this change warrants user-facing release notes and have added them to RELEASE-NOTES.txt if necessary.

@itsmeichigo itsmeichigo added this to the 23.4 ❄️ milestone Oct 13, 2025
@itsmeichigo itsmeichigo added the type: crash The worst kind of bug. label Oct 13, 2025
@dangermattic
Copy link
Collaborator

dangermattic commented Oct 13, 2025

1 Warning
⚠️ This PR is assigned to the milestone 23.4 ❄️. The due date for this milestone has already passed.
Please assign it to a milestone with a later deadline or check whether the release for this milestone has already been finished.

Generated by 🚫 Danger

@wpmobilebot
Copy link
Collaborator

wpmobilebot commented Oct 13, 2025

App Icon📲 You can test the changes from this Pull Request in WooCommerce iOS Prototype by scanning the QR code below to install the corresponding build.

App NameWooCommerce iOS Prototype
Build Numberpr16237-e1dcda9
Version23.4
Bundle IDcom.automattic.alpha.woocommerce
Commite1dcda9
Installation URL78078dtsjcm9g
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

guard let self else { return nil }

let retriedRequestIndex = _retriedJetpackRequests.firstIndex { retriedRequest in
let urlRequest = try? originalRequest.asURLRequest()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small notice, might be negligible as _retriedJetpackRequests could be a few items, but we could move parsing originalRequest outside firstIndex so it only runs once.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! I moved the parsing of originalRequest to outside of the firstIndex block in b63ea52.

let retriedRequestIndex = _retriedJetpackRequests.firstIndex { retriedRequest in
let urlRequest = try? originalRequest.asURLRequest()
let retriedRequest = try? retriedRequest.request.asURLRequest()
return urlRequest == retriedRequest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relying on == for URLRequest may compare unstable fields, like header order. This can cause misses where the request is present but not found. However, I'm not sure what the intentions are here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, just want to point out, that if both try? are nil, we match the request to the original. Is this intended?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with both of your points - updated the implementation in b63ea52.

}

// Force threads to start as close together as possible
group.wait()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small note — the group.wait() here doesn’t actually make the threads start together; it just waits for them to finish. In this case, that’s probably fine since the goal is to ensure no crash under load, but I just wanted to flag it in case a true concurrent start was intended.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the comments in ed4f8fa, sorry for the misleading notes.

Copy link
Contributor

@adborbas adborbas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had some small comments, but otherwise, good job! I've tested as described.

@itsmeichigo
Copy link
Contributor Author

itsmeichigo commented Oct 13, 2025

@adborbas Thanks for the great reviews! I added subsequents commits to address the issues. Please feel free to take another look - I'll merge tomorrow.

@itsmeichigo itsmeichigo merged commit cc5c514 into release/23.4 Oct 14, 2025
13 checks passed
@itsmeichigo itsmeichigo deleted the woomob-1450-crash-race-condition branch October 14, 2025 03:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: crash The worst kind of bug.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants